
#include "btl_poweron.h"
#include "app_init.h"

#if 1
#define BTL_CHIP_TYPE   0x41
#define I2C_COM_ERR     0
#define I2C_COM_SUCESS  1
#define FALSH_PAGE 256
#define BTL_BIN_VER_OFFSET (0xfc2a)

#define HAL_ERR     0
#define HAL_OK  1

uint16_t wCheckSum = 0x00;
#if 1
uint8_t BTL_I2CSendRecvEx(uint16_t addr, uint8_t *wBuf, uint16_t wLen, uint8_t *rBuf, uint16_t rLen)
{
    uint8_t ret , result;
    uint8_t i2c_addr = (addr << 1);

    result = HAL_ERR;
    if (NULL != wBuf && wLen > 0)
    {
		
		ret = app_iic_write(i2c_addr, wBuf, wLen);

		if(ret==CSI_OK)
		{
			
				
			if (rLen > 0 && NULL != rBuf)
			{
				udelay(50*wLen);
				if (CSI_OK == app_iic_read(i2c_addr, rBuf, rLen))
				{
					result = HAL_OK;
				}
			}
			else
			{
				result = HAL_OK;
			}
		}
       
    }
    return result;
}

#endif
uint8_t IICWriteReg(uint8_t regAddr, uint8_t regVal)
{
    uint8_t wBuf[2];

    wBuf[0] = regAddr;
    wBuf[1] = regVal;
//	if(app_iic_write( BTL_IIC_ADDR<<1,wBuf, 2))
//	{
//		return 0;
//	}
//	return 1;
    return  BTL_I2CSendRecv(wBuf, 2, NULL, 0);
}
uint8_t IICReadReg(uint8_t regAddr, uint8_t *rBuf, uint8_t len)
{
//	if(app_iic_read_register(BTL_IIC_ADDR<<1,regAddr,1, rBuf, len))
//	{
//		return 0;
//	}
//	return 1;
    return  BTL_I2CSendRecv(&regAddr, 1, rBuf, len);

}
static void SoftReset(void)
{
    uint8_t i;
    uint8_t ucRestCmd[2], ucReadByte;
    ucRestCmd[0]=0x52;
    ucRestCmd[1]=0x52;

    for (i=0; i < 3;i++)
    {
        IICWriteReg(0xa5, 0);
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(ucRestCmd, 2, &ucReadByte, 1))
        {
            if (0x52 == ucReadByte)
            {
                break;
            }
        }
        mdelay(20);

    }
}

uint8_t EnterBurnMode()
{
    static uint8_t bInit = 0;
    static uint8_t szCmdBuf[210] = { 0x00 };
    uint32_t i;
    uint8_t ret;

    if (0 == bInit) {
        bInit = 1;
        for (i = 0; i < sizeof(szCmdBuf); i += 2) {
            szCmdBuf[i] = 0x5A;
            szCmdBuf[i + 1] = 0xA5;
        }
    }

    ret = BTL_I2CSendRecv(szCmdBuf, sizeof(szCmdBuf), NULL, 0);

    return ret;
}
uint8_t ExitBurnMode()
{
    static uint8_t sExitBurnModeCmd[] = { 0x5a, 0xa5,  0x5a, 0xa5,  0x5a, 0xa5};
    uint8_t retry;
    for (retry =0; retry < 3; retry++)
    {
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(sExitBurnModeCmd, sizeof(sExitBurnModeCmd), NULL, 0))
        {
            mdelay(30);
            return I2C_COM_SUCESS;
        }
    }
    return I2C_COM_ERR;

}
uint8_t ReadChipTypeInternal(uint8_t *pChipType)
{
    static uint8_t szChipIDCmd[] = { 0x0A, 0xF5, 0xE7 };

    return BTL_I2CSendRecv(szChipIDCmd, sizeof(szChipIDCmd), pChipType, 1);
}
void ExitWriteFlashMode(void)
{
//    uint16_t i;
    uint8_t szChipIDCmd[256];

    memset(szChipIDCmd, 0xff, 256);

    if (I2C_COM_ERR == BTL_I2CSendRecv(szChipIDCmd, 256, NULL, 0))
    {
        //TP_LOG_PRINTF("ExitWriteFlashMode err\r\n");
        mdelay(50);
        BTL_I2CSendRecv(szChipIDCmd, 256, NULL, 0);
    }
}
uint8_t CheckHidDesc(uint8_t *pbType, uint8_t *pFwVer)
{
    uint8_t hidDescCmd[] = {0x01, 0x00};
    uint8_t hidDesc[30];
    uint8_t errCode;
    uint8_t retry;


    *pbType = 0;

    for (retry =0; retry < 3; retry++)
    {
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(hidDescCmd, sizeof(hidDescCmd), hidDesc, 30))
        {
            if (hidDesc[20]==0x7d && hidDesc[21]==0x34   && hidDesc[23]==0x78)
            {
                *pbType = 1;
                *pFwVer = hidDesc[24];
                TP_LOG_PRINTF("vid :%02x%02x, pid:%02x%02x\r\n", hidDesc[21],hidDesc[20], hidDesc[23],hidDesc[22]);
                errCode = BTL_ERR_OK;
                break;
            }
            else
            {
                errCode = BTL_ERR_CHIPID_UNMATCHED;
            }
        }
        else
        {
            errCode = BTL_ERR_IIC_COM_FAIL;
        }
        mdelay(20);
    }

    return errCode;
}
uint8_t ReadIcFirmwareVer(uint8_t fwVer[2]);

uint8_t BTLCheckTpChip(uint8_t *pChipType, uint8_t *pFwVer)
{
    static uint8_t szChipIDCmd[] = { 0x0A, 0xF5, 0xE7 };
    uint8_t chipType;
    uint8_t retry =0;
    uint8_t ret ;
    do
    {
        ret = BTL_ERR_OK;
        chipType = 0;
        *pChipType = 0;
        *pFwVer = 0xff;
		
		app_iwt_clr();
        //make sure exit write flash mode
        ExitWriteFlashMode();
        mdelay(20);


        if (I2C_COM_ERR == BTL_I2CSendRecv(szChipIDCmd, sizeof(szChipIDCmd), &chipType, 1))
        {
            ret = BTL_ERR_IIC_COM_FAIL;
            break;
        }
		mdelay(1);
        if (BTL_CHIP_TYPE != chipType)
        {
            //read hid descriptor
            if (BTL_ERR_OK == CheckHidDesc(&chipType, pFwVer) && chipType)
            {
                *pChipType = 1;
                TP_LOG_PRINTF("hid ver:%02x\r\n", *pFwVer);
                break;
            }
			app_iwt_clr();
            if (I2C_COM_ERR == EnterBurnMode())
            {
                ret = BTL_ERR_IIC_COM_FAIL;
                break;
            }
            mdelay(6);
            for (retry = 0; retry < 3; retry++)
            {
                if (I2C_COM_SUCESS == BTL_I2CSendRecv(szChipIDCmd, sizeof(szChipIDCmd), &chipType, 1))
                {
                    break;
                }
            }
        }
        if (BTL_CHIP_TYPE == chipType)
        {
            //btl tp deteced
            TP_LOG_PRINTF("chiptype:%02x\r\n", chipType);
            *pChipType = 1;
        }
        else
        {
            ret = BTL_ERR_CHIPID_UNMATCHED;
        }
        mdelay(20);
        if (I2C_COM_ERR == ExitBurnMode())
        {
            ret = I2C_COM_ERR;
            break;
        }
        mdelay(60); //wait to reboot
    } while(0);

    return ret;
}
uint8_t Switch2NormalIIC(void)
{
    const uint8_t szNormalIicCmd[] = {0x55, 0x46, 0x4F};//{ 'U', 'F', 'O'};
    uint8_t retry =0;
    //uint8_t fwVer[2];

    for (retry = 0; retry < 3; retry++)
    {
        //IICWriteReg(0x00, 0x00); //wakeup
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(szNormalIicCmd, sizeof(szNormalIicCmd), NULL, 0))
        {
            TP_LOG_PRINTF("switch to normal iic\r\n");
            return I2C_COM_SUCESS;
        }
    }

	return I2C_COM_ERR;
}
uint8_t Switch2HidIIC(void)
{
	const uint8_t szHidIicCmd[] = {0x6A, 0x01};
	uint8_t retry =0;
    
    for (retry = 0; retry < 3; retry++)
    {
        
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(szHidIicCmd, sizeof(szHidIicCmd), NULL, 0))
        {
            TP_LOG_PRINTF("switch to hid iic\r\n");
            return I2C_COM_SUCESS;
        }
    }
	return I2C_COM_ERR;
}

uint8_t ReadIcFirmwareVer(uint8_t fwVer[2])
{
    const uint8_t szChipIDCmd = 0xB6;
    uint8_t retry =0;
    //uint8_t fwVer[2];

    Switch2NormalIIC();

    mdelay(1);
    for (retry = 0; retry < 3; retry++)
    {
        if (I2C_COM_SUCESS == IICReadReg(szChipIDCmd, fwVer, 2))
        {
            return I2C_COM_SUCESS;
        }
    }
	Switch2HidIIC();
    return I2C_COM_ERR;
}
uint8_t EraseFlash(void)
{
    const uint8_t szChipIDCmd[] = { 0x09, 0xF6};
    uint8_t retry =0;

    for (retry =0; retry < 3; retry++)
    {
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(szChipIDCmd, sizeof(szChipIDCmd), NULL, 0))
        {
            return I2C_COM_SUCESS;
        }
    }

    return I2C_COM_ERR;
}
uint8_t UpdateBin2Flash(const uint8_t *pBinfile, uint32_t fileSize)
{
    uint32_t i, pageCnt, pageOffset;
    uint8_t burnBuf[FALSH_PAGE + 6];
    uint8_t ret, chipType;
    uint8_t fwBuf[FALSH_PAGE];
    do
    {
		Switch2NormalIIC();
		
        mdelay(5);
        EnterBurnMode();
        mdelay(5);
//        if (0 == EraseFlash())
//        {
//            ret = I2C_COM_ERR;
//            break;
//        }
//        mdelay(60);

        ReadChipTypeInternal(&chipType);
        TP_LOG_PRINTF("burnchiptype :%02x\r\n", chipType);
        mdelay(40);

        burnBuf[0] = 0x0f;
        burnBuf[1] = 0xf0;

        pageCnt = (fileSize+FALSH_PAGE-1)/FALSH_PAGE;;
        pageOffset = 0;
		wCheckSum=0;
        for (i =0; i< pageCnt; i++)
        {
			app_iwt_clr();
            pageOffset = i*FALSH_PAGE;
            burnBuf[2] = (uint8_t)(pageOffset >> 8);
            burnBuf[3] = (uint8_t)(pageOffset&0xff);
            pageOffset += FALSH_PAGE-1;
            burnBuf[4] = (uint8_t)(pageOffset >> 8);
            burnBuf[5] = (uint8_t)(pageOffset&0xff);

//            memcpy(burnBuf+6, pBinfile+i*FALSH_PAGE, FALSH_PAGE);
            app_spi_flash_page_read(WN8012_TP_OTA_DATA_ADDRESS+i*FALSH_PAGE, fwBuf, 64);
			
            app_spi_flash_page_read(WN8012_TP_OTA_DATA_ADDRESS+i*FALSH_PAGE+64, fwBuf+64, 64);
			
            app_spi_flash_page_read(WN8012_TP_OTA_DATA_ADDRESS+i*FALSH_PAGE+128, fwBuf+128, 64);
			
            app_spi_flash_page_read(WN8012_TP_OTA_DATA_ADDRESS+i*FALSH_PAGE+192, fwBuf+192, 64);
//            memcpy(burnBuf+6, fwBuf, FALSH_PAGE);
			for(uint16_t j=0;j<FALSH_PAGE;j++)
			{
				burnBuf[6+j]=fwBuf[j];
			}
            if (i == pageCnt -1)
            {
                memset(burnBuf+(fileSize - i*FALSH_PAGE + 6), 0xff, (pageCnt*FALSH_PAGE - fileSize));
            }
            if (I2C_COM_ERR== BTL_I2CSendRecv(burnBuf, sizeof(burnBuf), NULL, 0))
            {
                ret = I2C_COM_ERR;
                break;
            }
            TP_LOG_PRINTF(".");
            mdelay(5);
			for (uint16_t j = 0; j < FALSH_PAGE; j++) {
				wCheckSum += fwBuf[j];
			}
        }
        TP_LOG_PRINTF("\r\n");
		app_iwt_clr();
        mdelay(20);
        ExitBurnMode();
		mdelay(40);
        ret = I2C_COM_SUCESS;
    }while(0);
    return ret;

}


uint8_t CheckBinCheckSum(const uint8_t *pBinfile, uint32_t fileSize)
{
    uint8_t retry =0;
    uint8_t checkSumArr[3];
    uint16_t wIcCheckSum;//wCheckSum = 0x00;
    uint32_t dwCheckSumSize = fileSize;
    uint32_t dwTotalSize = 64*1024;
    uint32_t i;

    Switch2NormalIIC();
    mdelay(2);
	uint8_t chipType;
	ReadChipTypeInternal(&chipType);
	mdelay(2);
        TP_LOG_PRINTF("burnchiptype :%02x\r\n", chipType);
    if (I2C_COM_ERR == IICWriteReg(0x8A, 0xaa))
    {
        return 0;
    }

    if (dwCheckSumSize > dwTotalSize) {
        dwCheckSumSize = dwTotalSize;
    }
//    for ( i = 0; i < dwCheckSumSize; i++) {
//	     wCheckSum += pBinfile[i];
//    }
//   	uint8_t fw_tmpdata[300];
//	for(i=0; i < dwCheckSumSize/256; i++){
//		app_iwt_clr();
//		app_spi_flash_page_read( (WN8012_TP_OTA_DATA_ADDRESS+i*256), fw_tmpdata, 256);
//
//		//256 byte OTA data32  half byteCRC
//		for(int j=0;j<256;j++){
//			 wCheckSum += fw_tmpdata[j];
//		}
////		udelay(40);
//	}
//    for (i = dwCheckSumSize; i < dwTotalSize; i++) {
//        wCheckSum += 0xff;
//    }
	app_iwt_clr();
//	app_spi_flash_page_read(0x30000,(uint8_t*)&wCheckSum,2);
//    mdelay(40);
	app_iwt_clr();
    for (retry =0; retry < 40; retry++)
    {
        if (I2C_COM_SUCESS == IICReadReg(0x3f, checkSumArr, 3)
            && 1 == checkSumArr[0])
        {
            break;
        }
		mdelay(10);
    }
    Switch2HidIIC();

    wIcCheckSum =(((uint16_t)checkSumArr[1])<<8) +checkSumArr[2];

    TP_LOG_PRINTF("checksum, r:%04x, b:%04x\r\n", wIcCheckSum, wCheckSum);
    if (1 == checkSumArr[0] && wIcCheckSum == wCheckSum)
    {
        return 1;
    }

    return 0;
}
void GetBinFirmwareVer(const uint8_t *pBinfile, uint32_t fileSize, uint8_t binFwVer[2])
{
//    binFwVer[0] = pBinfile[BTL_BIN_VER_OFFSET];
//    binFwVer[1] = pBinfile[BTL_BIN_VER_OFFSET+1];
    app_spi_flash_page_read(WN8012_TP_OTA_DATA_ADDRESS + BTL_BIN_VER_OFFSET, binFwVer, 2);
}
uint8_t BtlTpModeSwitch(uint8_t mode)
{
    const uint8_t mode_ptp_to_mouse[] = {0x22,0x00,0x33,0x03,0x23,0x00,0x04,0x00,0x03,0x00};
    const uint8_t mode_mouse_to_ptp[] = {0x22,0x00,0x33,0x03,0x23,0x00,0x04,0x00,0x03,0x03};
    const uint8_t hid_desc[]={0x01,0x00};
    uint8_t i, ucReadByte, errCode;

    errCode = BTL_ERR_IIC_COM_FAIL;
    for (i=0; i < 3;i++)
    {
        if (I2C_COM_SUCESS == BTL_I2CSendRecv(hid_desc, 2, &ucReadByte,1))
        {
            if (ucReadByte == 0x1e)
            {
                if (0 == mode) //ptp mode -> mouse mode
                {
                    BTL_I2CSendRecv(mode_ptp_to_mouse, sizeof(mode_ptp_to_mouse), NULL, 0);
                }
                else
                {
                    BTL_I2CSendRecv(mode_mouse_to_ptp, sizeof(mode_mouse_to_ptp), NULL, 0);
                }
                errCode = BTL_ERR_OK;
                break;
            }
            else
            {
                mdelay(10);
            }
        }
        else
        {
            break;
        }
    }

    return errCode;
}

uint8_t BTLFirmwareUpdateCheck(uint8_t *pIcFwVer)
{
    uint8_t ret, errCode;
    uint8_t icFwVer[2], binFwVer[2];
    uint8_t burnType;

    do
    {
        errCode = BTL_ERR_OK;

        //step 2 check  bin firmware ver
        GetBinFirmwareVer(BTL_FW_BIN, BTL_FW_BIN_LEN,binFwVer);
        if ((0x00 == binFwVer[0] || binFwVer[0] >= 0x80)  && 0xff != binFwVer[0])
        {
            //inlvaid bin ver, do not update
            errCode = BTL_ERR_BIN_FMT_INVALID;
			TP_LOG_PRINTF("bin ver:%02x %02x\r\n", binFwVer[0],binFwVer[1]);
            break;
        }else if( 0xff == binFwVer[0]){
			 //inlvaid bin ver, do not update
            errCode = BTL_ERR_BIN_FMT_INVALID;
			TP_LOG_PRINTF("bin ver:%02x %02x\r\n", binFwVer[0],binFwVer[1]);
            break;
		}
        //valid bin firmwared detected

        //step 3 check ic-internal firmware ver
        if (0xff == pIcFwVer[0])
        {
            ret = ReadIcFirmwareVer(pIcFwVer);
        }
        else
        {
            ret = I2C_COM_SUCESS;
        }
        TP_LOG_PRINTF("bin ver:%02x, ic ver:%02x\r\n", binFwVer[0],pIcFwVer[0]);

        burnType = 0;
        if (I2C_COM_SUCESS == ret )
        {
            if (pIcFwVer[0] == 0x00  || pIcFwVer[0] >= 0x80)
            {
                //inlvaid ver, force update
                burnType = 1;
            }
            else if (pIcFwVer[0] < binFwVer[0])
            {
                //bin is newer
                burnType = 1;
            }
        }
        else
        {
            //iic communication fail
            errCode = BTL_ERR_VER_READ_FAIL;
            break;
        }
		
//		if(0==burnType)
//		{
//			if (0 == CheckBinCheckSum(BTL_FW_BIN,BTL_FW_BIN_LEN))
//			{
//				//bin checksum err
//				errCode = BTL_ERR_CHECKSUM_FAIL;
//				burnType=1;
//			}
//		}

        //step 4 update firmware
        if (1 == burnType)
        {
            if (0 == UpdateBin2Flash(BTL_FW_BIN,BTL_FW_BIN_LEN))
            {
                errCode = BTL_ERR_UPDATE_FAIL;
                break;
            }

            if (0 == CheckBinCheckSum(BTL_FW_BIN,BTL_FW_BIN_LEN))
            {
                //bin checksum err
                errCode = BTL_ERR_CHECKSUM_FAIL;
                break;
            }
            //update ok
            TP_LOG_PRINTF("Update Fw Finish\r\n");
            errCode = BTL_ERR_FW_UPDATED;
        }
        else
        {
//            SoftReset();
//            mdelay(30);
            errCode = BTL_ERR_NEED_NOT_UPDATE;
            TP_LOG_PRINTF("Need not Update\r\n");
        }
    }while(0);
    return errCode;
}


uint8_t BTLTpPowerOnCheck(void)
{
    uint8_t errCode, isBtlTp, fwVer[2];

    //check chip-type, 1:btl-tp, 0: unkown
    errCode = BTLCheckTpChip(&isBtlTp, fwVer);


    if (BTL_ERR_OK == errCode && 1 == isBtlTp)
    {
		TP_version=fwVer[0];
        errCode = BTLFirmwareUpdateCheck(fwVer);
    }

    TP_LOG_PRINTF("BTL PowerOn ErrCode : %d\r\n\r\n", errCode);
	
	BtlTpModeSwitch(1);
	
//	uint32_t dwCheckSumSize=64*1024;
//	
//	uint8_t fw_tmpdata[300];
//	uint16_t wCheckSum=0;
	
//	for(uint8_t i=0; i < dwCheckSumSize/256; i++){
//		app_iwt_clr();
//		app_spi_flash_page_read( (WN8012_TP_OTA_DATA_ADDRESS+i*256), fw_tmpdata, 256);
//
//		//256 byte OTA data32  half byteCRC
//		for(int j=0;j<256;j++){
//			 wCheckSum += fw_tmpdata[j];
//		}
////		udelay(40);
//	}
//
//    TP_LOG_PRINTF("checksum, b:%04x\r\n", wCheckSum);


//	for(uint16_t i=0; i < dwCheckSumSize/256; i++){
//		app_iwt_clr();
//		app_spi_flash_page_read( (WN8012_TP_OTA_DATA_ADDRESS+i*256), fw_tmpdata, 256);
//		app_iwt_clr();
//		one_wire_bus_uart_send_one_packet(fw_tmpdata,256);
//		 while(release_tx_flag==0)
//		 {
//			 
//		 };
//		if(release_tx_flag == 0x01)
//		{
//			release_tx_flag = 0;
//		}
//			
//
//	}
    return errCode;
}
#endif

